import log from './log';
import env from './env';

let whetherCheckToken = true; // 是否检查Token
let whetherVerifyToken = true; // 是否校验token

let preventingRepeatLogins = true; // 防止重复登录
let preventingMultipleLogins = false; // 防止多次登录

let requestQueue = []; // 网络请求队列

let loginNumber = 0; // 记录登录次数
let requestNumber = 0; // 请求数量


/**
 * 重试原始请求
 */
function retryOriginalRequest(reqUrl, req) {
  const retryOriginalRequest = new Promise((resolve, reject) => {
    addRequestQueue(() => {
      resolve(request(reqUrl, req));
    });
  });
  return retryOriginalRequest;
}

/**
 * 加入请求队列
 */
function addRequestQueue(callback) {
  requestQueue.push(callback);
}

/**
 * 网络请求判断token
 */
const request = (reqUrl, req) => {
  // 是否进行token校验
  if (whetherCheckToken) {
    if (!wx.getStorageSync('token')) {
      logins();
      return retryOriginalRequest(reqUrl, req);
    } else {
      if (whetherVerifyToken) {
        // 是否允许调用token校验，防止多接口请求，重复调用检验token接口
        whetherVerifyToken = false;
        checkToken();
      }
      return retryOriginalRequest(reqUrl, req);
    }
  } else {
    return createPromiseReq(reqUrl, req);
  }
}

/**
 * 创建 promise 封装的wx.request网络请求
 */
const createPromiseReq = (reqUrl, req) => {
  if (req.showLoading) {
    wx.showLoading({
      title: '正在加载...',
      mask: true
    });
    requestNumber = requestNumber + 1;
  } // 获取配置请求参数

  let reqParam = getConfigReqParam(reqUrl, req);
  return new Promise((resolve, reject) => {
    wx.request({
      url: reqParam.requestUrl,
      // 网络请求地址
      data: reqParam.data,
      // 网络请求参数
      header: reqParam.header,
      // 网络请求头
      method: req.method,
      // 网络请求类型
      success: (res) => {
        // 网络请求成功回调
        hideLoadingFun(req.showLoading); //  其余HTTP status 打印错误日志
        if (res.statusCode != '200' && res.statusCode != '401') {
          log.error(reqUrl, reqParam.data, res.data);
          return;
        }

        if (res.statusCode == '401') {
          refreshToken();
          resolve(retryOriginalRequest(reqUrl, req));
          return;
        }

        if (res.statusCode == '200') {
          // 检查返回 HTTP Header头里是否有token 有的话替换存储里的token
          if ((res.header.token != null && res.header.token != '') || (res.header.Token != null && res.header.Token != '')) {
            wx.setStorageSync('token', res.header.token ? res.header.token : res.header.Token);
          } //服务端返回业务状态码

          let code = res.data.code; //服务端返回业务数据报文 V1 V4 不同

          let rsBody = res.data;

          if (code != undefined && code != '' && code == 'PR0000') {
            resolve(res.data);
          } else {
            log.error('业务状态码不等于PR0000', reqUrl, reqParam.data, rsBody); // 如果调用方定义 fail 回调 执行调用方 fail 函数， 否则统一 showtoast
            if (req.fail) {
              reject(res.data);
            } else {
              wx.showToast({
                title: res.data.message,
                icon: 'none',
                mask: true
              });
            }
          }
        }
      },
      fail: (err) => {
        // 网络请求失败回调
        hideLoadingFun(req.showLoading); // 打印实时错误日志
        log.error('http请求未成功', reqUrl, reqParam.data, err);
        reject(err);
      }
    });
  });
};

/**
 * 刷新token
 */
function refreshToken() {
  wx.removeStorageSync('token');
  logins();
  return;
}

/**
 * 隐藏showLoading加载框
 */
function hideLoadingFun(showLoading) {
  //无论成功失败 把请求次数减1 直到为0 隐藏加载框
  if (showLoading) {
    requestNumber = requestNumber - 1;

    if (requestNumber == 0 || requestNumber < 0) {
      wx.hideLoading();
    }
  }
}

/**
 * 免登接口 函数
 */
function logins() {
  if (!preventingRepeatLogins || preventingMultipleLogins) {
    return;
  }
  preventingRepeatLogins = false;
  return new Promise((resolve, reject) => {
    wx.login({
      success: (resLogin) => {
        if (!resLogin.code) {
          wx.showToast({
            title: '获取用户code凭证失败',
            icon: 'none'
          });
          return;
        }
        let data = {
          jscode: resLogin.code,
        };
        let param = getConfigReqParam('CL060101', data);
        wx.request({
          url: param.requestUrl,
          data: param.data,
          header: param.header,
          method: 'POST',
          success: (res) => {
            if (loginNumber == 1) {
              preventingMultipleLogins = true;
              requestQueue = [];
            }

            preventingRepeatLogins = true;
            whetherCheckToken = false;

            if (res.header.token || res.header.Token) {
              loginNumber = 0;
              preventingMultipleLogins = false;
              wx.setStorageSync('token', res.header.token ? res.header.token : res.header.Token);
            } else {
              loginNumber++;
            }
            onAccessTokenFetched();
            resolve(res.data);
          },
          fail: (err) => {
            log.error('小程序插件登录失败---', err);
            reject(err);
            wx.showToast({
              title: '登录失败',
              icon: 'none'
            });
          }
        });
      },
      fail: (err) => {
        reject('获取用户code API失败');
        wx.showToast({
          title: '获取用户code API失败',
          icon: 'none'
        });
      }
    });
  });
}

/**
 * 当成功获取token 后 循环执行网络请求队列
 */
function onAccessTokenFetched() {
  preventingRepeatLogins = true; //设置
  requestQueue.forEach((callback) => {
    callback();
  });
  requestQueue = [];
}

/**
 * 校验token
 */
function checkToken() {
  let param = getConfigReqParam('CL280103', {});
  wx.request({
    url: param.requestUrl,
    data: param.data,
    header: param.header,
    method: 'POST',
    success: (res) => {
      if (res.statusCode == '401') {
        refreshToken();
        return;
      }
      if (res.header.token != null && res.header.token != '') {
        wx.setStorageSync('token', res.header.token);
      }

      whetherCheckToken = false;
      onAccessTokenFetched();
    },
    fail: (err) => {
      if (err.statusCode == '401') {
        refreshToken();
        return;
      }
    }
  });
}

/**
 * 获取配置请求参数
 */
function getConfigReqParam(url, req) {
  // 定义网络请求头
  let header = {
    'Content-Type': 'application/json',
    appid: 'wxd8075440765922db'
  };
  // 为请求头添加token 如果传入了不设置token 则跳过
  if (wx.getStorageSync('token')) {
    header.Authorization = 'Bearer ' + wx.getStorageSync('token');
  }

  return {
    requestUrl: env.getBaseRequestURLV4() + url,
    header: header,
    data: configReqParam(req.data ? req.data : req)
  };
}

/**
 * 配置请求信息
 */
function configReqParam(data) {
  let param = data != undefined ? data : {};
  return param;
}

/**
 * 封装get请求函数
 */
const get = (reqUrl, req) => {
  return request(reqUrl, {
    method: 'GET',
    data: req.data
  });
};

/**
 * 封装post请求函数
 */
const post = (reqUrl, req) => {
  return request(reqUrl, {
    method: 'POST',
    data: req.data,
    showLoading: req.showLoading,
    fail: req.fail,
  });
};

module.exports = {
  get,
  post,
  logins,
  checkToken
};